# Подтипы

В программировании, для некоторых задач распространены key-value базы данных. Внешне они работают по принципу словарей, но живут как отдельные программы и умеют делать много полезного: например, сохранять данные на диск, переносить данные между машинами в сети и тому подобное.

В целях тестирования бывает полезно иметь реализацию такой базы данных с таким же интерфейсом, но которая хранит данные в памяти, а не во внешнем хранилище. Это позволяет легко сбрасывать состояние между тестами и не замедлять их. В этом упражнении вам предстоит реализовать такую базу данных.

## main/java/exercise/InMemoryKV.java

## Задачи

* Реализуйте класс `InMemoryKV`, который представляет собой in-memory key-value хранилище. Данные внутри него хранятся в обычном словаре `Map`. Класс должен реализовывать интерфейс `KeyValueStorage`. Конструктор класса принимает на вход словарь `Map`, который становится начальным значением базы данных. Ключи и значения в словаре представлены строками. Интерфейс этого класса вы можете посмотреть в файле *main/java/exercise/KeyValueStorage.java*.

  Реализуйте в классе следующие интерфейсные методы:

  * `set()` — добавляет в словарь новое значение по указанному ключу (или меняет значение, если ключ уже существует).
  * `unset()` — удаляет из словаря значение по переданному ключу
  * `get()` — возвращает значение по указанному ключу. Если такого ключа в словаре нет, возвращает значение по умолчанию.
  * `toMap()` — возвращает базу данных в виде словаря `Map`.

  ```java
  KeyValueStorage storage = new InMemoryKV(Map.of("key", "10"));
  // Получение значения по ключу
  storage.get("key", "default"); // "10"
  storage.get("unknown", "default"); // "default"
  // Установка нового значения
  storage.set("key2", "value2");
  storage.get("key2", "default"); // "value2"
  // Удаление ключа
  storage.unset("key2");
  storage.get("key2", "default"); // "default"
  // Получение всех данных из базы
  Map<String, String> data = storage.toMap();
  System.out.println(data); // => {key=10};
  ```

## main/java/exercise/App.java

## Задачи

* Создайте класс `App` с публичным статическим методом `swapKeyValue()`. Метод принимает на вход объект базы данных и меняет в нём ключи и значения местами. `swapKeyValue()` — полиморфный метод, он может работать с любой реализацией базы данных, реализующей интерфейс `KeyValueStorage`.

```java
KeyValueStorage storage = new InMemoryKV(Map.of("key", "value", "key2", "value2"));
App.swapKeyValue(storage);
storage.get("key", "default"); // "default"
storage.get("value", "default"); // "key"

System.out.println(storage.toMap()); // => {value=key, value2=key2}
```

## Подсказка

* Изучите тесты

## Самостоятельная работа

* В файле *main/java/exercise/FileKV.java* реализуйте класс `FileKV`. Класс представляет key-value базу данных, которая сохраняет свои данные на диске в указанном файле. Этот класс тоже должен реализовывать интерфейс `KeyValueStorage`. Конструктор класса принимает два аргумента:

  * Путь до файла, в котором будут храниться данные (строка)
  * Словарь `Map`, который будет начальным значением базы данных. Ключи и значения в словаре также представлены строками.

  ```java
  KeyValueStorage storage = new FileKV("src/test/resources/file", Map.of("key", "value"));
  // Получение значения по ключу
  storage.get("key", "default"); // "value"
  ```

  В процессе работы вам потребуется выполнить сериализацию (представление данных в виде строки) и десериализацию словаря `Map`. Удобнее всего представлять словарь в виде JSON. Для этого в классе `Utils` уже написаны методы `Utils.serialize()` и `Utils.unserialize()`. Для чтения и записи файлов также имеются уже написанные методы `Utils.readFile()` и `Utils.writeFile()`. 

* В файле  *src/test/java/exerciseFileKVTest* допишите тесты на эту реализацию базы данных.
